package com.halflife.pay.wxpay;

import com.alibaba.fastjson.JSON;
import com.halflife.comeElectricity.member.rider.Wxkey;
import com.halflife.framework.exception.BusinessException;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

public class WXPayAgent {
    public static final Logger log = LoggerFactory.getLogger(WXPayAgent.class);


    private WXPay wxpay;
    private WXPayConfigImpl config;
    private String out_trade_no;
    private String total_fee;
    //微信退款
    private String out_refund_no;//商户退款单号
    private String refund_fee;//退款金额
    private String refund_desc;//退款原因
    private String transaction_id;//微信订单号
    public WXPayAgent(){}

    public WXPayAgent(String out_trade_no, Integer payMoney) throws Exception {
        config = WXPayConfigImpl.getInstance();
        wxpay = new WXPay(config);
        total_fee = String.valueOf(payMoney);
        this.out_trade_no = out_trade_no;
    }
    //微信退款构造方法
    public WXPayAgent(String out_trade_no, String transaction_id, Integer payMoney,Integer refundMoney,String out_refund_no, String refund_desc) throws Exception{

        config = WXPayConfigImpl.getInstance();
        wxpay = new WXPay(config);
        this.total_fee = String.valueOf(payMoney);
        this.out_trade_no = out_trade_no;
        this.out_refund_no = out_refund_no;
        this.refund_fee = String.valueOf(refundMoney);
        this.refund_desc = refund_desc;
        this.transaction_id = transaction_id;
    }
//    {nonce_str=ZpM46ynyXckHx1gT, device_info=WEB, appid=wx4ac466b613e7d418, sign=B1E19B957C3281E466F6C5CFE7BB12A691158B9A6F317081932DF9011D343A4D, trade_type=APP, return_msg=OK, result_code=SUCCESS, mch_id=1499066262, return_code=SUCCESS, prepay_id=wx201803160031342fd811681e0612394617}

    public Map doGzhUnifiedOrder(String openId) {
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("body", "货达充值");
        data.put("out_trade_no", out_trade_no);
//        data.put("detail", "");//非必需
        data.put("appid", config.getGzhAppID());//最后统一加上
        data.put("openid", openId);//最后统一加上
//        data.put("openid", "o-Z-D1BHMWxwIOeCJZrTqqYN7Euc");//最后统一加上
//        data.put("mch_id", "WEB");//最后统一加上
        data.put("device_info", "WEB");
        data.put("fee_type", "CNY");
        data.put("total_fee", this.total_fee);
        data.put("spbill_create_ip", "39.106.222.114");
        //APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP。
        //接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参
        data.put("notify_url", "https://39.106.222.114/mc_order/notify.do");
        //trade_type=NATIVE，此参数必传。此id为二维码中包含的商品ID，商户自行
        data.put("trade_type", "JSAPI");

        try {
            String noncestr = WXPayUtil.generateUUID();
            data.put("nonce_str", noncestr);
            Map<String, String> r = wxpay.unifiedOrder(data);
            if("FAIL".equals(r.get("return_code"))){
                throw new BusinessException("==支付异常"+r.get("return_msg"));
            }

            StringBuffer weiXinVo = new StringBuffer();
            long currentTimeMillis = System.currentTimeMillis();//生成时间戳
            long second = currentTimeMillis / 1000L;//（转换成秒）

            String seconds = String.valueOf(second).substring(0, 10);//（截取前10位）
            SortedMap<String, String> signParam = new TreeMap<String, String>();
            signParam.put("appId", this.config.getGzhAppID());//app_id

            signParam.put("timeStamp", seconds);//北京时间时间戳
            signParam.put("nonceStr", noncestr);//自定义不重复的长度不长于32位
//            signParam.put("partnerid", this.config.getMchID());//微信商户账号
//            signParam.put("prepayid", r.get("prepay_id"));//预付订单id
            signParam.put("package", "prepay_id="+r.get("prepay_id"));//默认sign=WXPay Sign=WXPay
            signParam.put("signType", "MD5");//北京时间时间戳
            String signAgain = WXPayUtil.generateSignature(signParam, config.getKey(), wxpay.signType);//再次生成签名
            signParam.put("paySign", signAgain);
            System.out.println(signAgain);
            r.forEach((String x, String y) -> {
                log.debug(x + "=====GZH===" + y);
            });
            signParam.forEach((String x, String y) -> {
                log.debug(x + "========" + y);
            });
            return signParam;
        } catch (Exception e) {
            e.printStackTrace();

        }
        return null;
    }

    /**
     * {openid=oG8ae4pv5fD7DOvBkkMju6CFGbnU, session_key=8DVqretW6/7hsysyPKV5rA==}
     * {errcode=40029, errmsg=invalid code, hints: [ req_id: 3Bpc04922273 ]}
     * @param code
     * @return
     */
    public static Map<String,String> getOpenId(String code) {
        Wxkey wxkey =  null;
        RestTemplate restTemplate = new RestTemplate();
        StringBuilder sb = new StringBuilder();
        sb.append("https://api.weixin.qq.com/sns/jscode2session");
        //老板
//      sb.append("?appid=").append("wx899777e9089a358d");//wx899777e9089a358d
//      sb.append("&secret=").append("257ceb9d0a306b601950297e691f4bca");
        sb.append("?appid=").append("wx4e05fa2d7f448ba7");//wx899777e9089a358d
        sb.append("&secret=").append("db3541d806ae9e071a552cdee54c285c");

        sb.append("&js_code=").append(code);
        sb.append("&grant_type=authorization_code");
        String xl = restTemplate.getForObject(sb.toString(),String.class);
        Map map = JSON.parseObject(xl, HashMap.class);
        return map;
    }

    /**
     * 扫码支付  下单
     */
    public Map doXcxUnifiedOrder(String openid)throws Exception {//oG8ae4pv5fD7DOvBkkMju6CFGbnU

        HashMap<String, String> data = new HashMap<String, String>();
        data.put("openid",openid);
        data.put("body", "购电充值");
        data.put("out_trade_no", out_trade_no);
        data.put("appid", config.getAppID());
        data.put("fee_type", "CNY");
        data.put("total_fee", this.total_fee);
        // 部署修改 001
//        data.put("spbill_create_ip", "39.106.222.114");
        data.put("spbill_create_ip", "47.105.65.229");
        //APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP。
        //接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参
        // 部署修改 001
//        data.put("notify_url", "https://www.huoyunsuda.com/electricity/rider_login/notify.do");
//        data.put("notify_url", "https://www.yunnenghulian.com/test/rider_login/notify.do");
        data.put("notify_url", "https://www.yunnenghulian.com/electricity/rider_login/notify.do");
        data.put("trade_type", "JSAPI");
        String noncestr = WXPayUtil.generateUUID();
        data.put("nonce_str", noncestr);
        Map<String, String> r = wxpay.unifiedOrder(data);//pay/unifiedorder
        if("FAIL".equals(r.get("return_code"))){
            throw new BusinessException("==支付异常"+r.get("return_msg"));
        }
        long currentTimeMillis = System.currentTimeMillis();//生成时间戳
        long second = currentTimeMillis / 1000L;//（转换成秒）
        String seconds = String.valueOf(second).substring(0, 10);//（截取前10位）
        SortedMap<String, String> signParam = new TreeMap<String, String>();
        signParam.put("appId", this.config.getAppID());//app_id
        signParam.put("package","prepay_id="+r.get("prepay_id") );//预付订单id
        signParam.put("signType", wxpay.signType.name());//默认sign=WXPay Sign=WXPay
        signParam.put("nonceStr", noncestr);//自定义不重复的长度不长于32位
        signParam.put("timeStamp", seconds);//北京时间时间戳
        String signAgain = WXPayUtil.generateSignature(signParam, config.getKey(), wxpay.signType);//再次生成签名
        signParam.put("paySign", signAgain);
        r.forEach((String x, String y) -> {
            log.debug(x + "========" + y);
        });
        signParam.forEach((String x, String y) -> {
            log.debug(x + "========" + y);
        });
        return signParam;
    }

    /**
     * 退款
     * 已测试 edit by liuj3
     */
    public String doRefund(String payType) throws Exception{
        HashMap<String, String> data = new HashMap<String, String>();
        if ("JSAPI".equals(payType)){
            data.put("appid", config.getGzhAppID());
        }else{
            data.put("appid", config.getAppID());
        }
        //data.put("out_trade_no", out_trade_no);
        data.put("transaction_id", transaction_id);
        data.put("out_refund_no", out_refund_no);
        data.put("total_fee", total_fee);
        data.put("refund_fee", refund_fee);
        data.put("refund_fee_type", "CNY");
        //data.put("op_user_id", config.getMchID());
        //退款原因
        data.put("refund_desc", refund_desc);
        data.put("notify_url", "https://www.yunnenghulian.com/electricity/rider_login/refundNotify.do");
//        data.put("notify_url", "http://39.106.222.114/mc_order/notify_.do");
        try {
            String noncestr = WXPayUtil.generateUUID();
            data.put("nonce_str", noncestr);
            Map<String, String> r = wxpay.refund(data);
            r.forEach((String x, String y) -> {
                log.debug(x + "========" + y);
            });
            if("FAIL".equals(r.get("return_code"))){
                log.error("================退款请求失败===================");
                throw new BusinessException("==支付异常"+r.get("return_msg"));
            }else if("SUCCESS".equals(r.get("return_code"))){
                if("FAIL".equals("result_code")){
                    log.error("================退款请求失败===================");
                    throw new BusinessException("==支付异常"+r.get("return_msg"));
                }
                log.error("================退款请求成功===================");
                //回写退款信息
                return r.get("refund_id");
            }
        } catch (Exception e) {
            log.error("======================退款失败===========================");
            log.error(e.toString());
            throw e;
        }
        return null;
    }

    public Map doUnifiedOrder() {
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("body", "货达充值");
        data.put("out_trade_no", out_trade_no);
//        data.put("detail", "");//非必需
        data.put("appid", config.getAppID());
//        data.put("appid", "WEB");//最后统一加上
//        data.put("mch_id", "WEB");//最后统一加上
        data.put("device_info", "WEB");
        data.put("fee_type", "CNY");
        data.put("total_fee", this.total_fee);
        data.put("spbill_create_ip", "39.106.222.114");
        //APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP。
        //接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参
        data.put("notify_url", "http://39.106.222.114/mc_order/notify.do");
        //trade_type=NATIVE，此参数必传。此id为二维码中包含的商品ID，商户自行
        data.put("trade_type", "APP");
        //data.put("product_id", "12");
        // data.put("time_expire", "20170112104120");

        try {
            String noncestr = WXPayUtil.generateUUID();
            data.put("nonce_str", noncestr);
            Map<String, String> r = wxpay.unifiedOrder(data);//pay/unifiedorder
            if("FAIL".equals(r.get("return_code"))){
                throw new BusinessException("==支付异常"+r.get("return_msg"));
            }

            StringBuffer weiXinVo = new StringBuffer();
            long currentTimeMillis = System.currentTimeMillis();//生成时间戳
            long second = currentTimeMillis / 1000L;//（转换成秒）

            String seconds = String.valueOf(second).substring(0, 10);//（截取前10位）
            SortedMap<String, String> signParam = new TreeMap<String, String>();
            signParam.put("appid", this.config.getAppID());//app_id
            signParam.put("partnerid", this.config.getMchID());//微信商户账号
            signParam.put("prepayid", r.get("prepay_id"));//预付订单id
            signParam.put("package", "Sign=WXPay");//默认sign=WXPay Sign=WXPay
            signParam.put("noncestr", noncestr);//自定义不重复的长度不长于32位
            signParam.put("timestamp", seconds);//北京时间时间戳


            String signAgain = WXPayUtil.generateSignature(signParam, config.getKey(), wxpay.signType);//再次生成签名

            SortedMap<String, String> signParam1 = new TreeMap<String, String>();
            signParam1.put("appid", this.config.getAppID());//app_id
            signParam1.put("noncestr", noncestr);//自定义不重复的长度不长于32位
            signParam1.put("package", "Sign=WXPay");//默认sign=WXPay Sign=WXPay
            signParam1.put("partnerid", this.config.getMchID());//微信商户账号
            signParam1.put("prepayid", r.get("prepay_id"));//预付订单id
            signParam1.put("timestamp", seconds);//北京时间时间戳
            String signAgain1 = WXPayUtil.generateSignature(signParam1, config.getKey(), WXPayConstants.SignType.MD5);//再次生成签名
            System.out.println(signAgain);
            System.out.println(signAgain1);

            signParam.put("sign", signAgain);
            System.out.println(signAgain);
            r.forEach((String x, String y) -> {
                log.debug(x + "========" + y);
            });
            signParam.forEach((String x, String y) -> {
                log.debug(x + "========" + y);
            });
            return signParam;
        } catch (Exception e) {
            e.printStackTrace();

        }
        return null;
    }

    private String getAppSign(Map<String, String> mapOrder, String timestamp) throws Exception{
        SortedMap<String, String> appParam = new TreeMap<String, String>();
        appParam.put("appid", mapOrder.get("appid").toString());
        appParam.put("partnerid", this.config.getMchID());
        appParam.put("prepayid", mapOrder.get("prepay_id").toString());
        appParam.put("package", "Sign=WXPay");
        appParam.put("noncestr", mapOrder.get("nonce_str"));
        appParam.put("timestamp", timestamp);
        return genAppSignMap(appParam);
    }
    public  String genAppSignMap(SortedMap<String, String> appParams)throws Exception {
        StringBuilder sb = new StringBuilder();
        for(Map.Entry<String, String> entry : appParams.entrySet()){
            sb.append(entry.getKey());
            sb.append('=');
            sb.append(entry.getValue());
            sb.append('&');
        }
        sb.append("key=");
        sb.append(this.config.getKey());//秘钥
        String appSign = WXPayUtil.MD5(sb.toString()).toUpperCase();
        return appSign;
    }


    public void doOrderClose() {
        System.out.println("关闭订单");
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("out_trade_no", out_trade_no);
        try {
            Map<String, String> r = wxpay.closeOrder(data);
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void doOrderQuery() {
        System.out.println("查询订单");
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("out_trade_no", out_trade_no);
//        data.put("transaction_id", "4008852001201608221962061594");
        try {
            Map<String, String> r = wxpay.orderQuery(data);
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void doOrderReverse() {
        System.out.println("撤销");
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("out_trade_no", out_trade_no);
//        data.put("transaction_id", "4008852001201608221962061594");
        try {
            Map<String, String> r = wxpay.reverse(data);
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 长链接转短链接
     * 测试成功
     */
    public void doShortUrl() {
        String long_url = "weixin://wxpay/bizpayurl?pr=etxB4DY";
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("long_url", long_url);
        try {
            Map<String, String> r = wxpay.shortUrl(data);
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /**
     * 查询退款
     * 已经测试
     */
    public void doRefundQuery() {
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("out_refund_no", out_trade_no);
        try {
            Map<String, String> r = wxpay.refundQuery(data);
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 对账单下载
     * 已测试
     */
    public void doDownloadBill() {
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("bill_date", "20161102");
        data.put("bill_type", "ALL");
        try {
            Map<String, String> r = wxpay.downloadBill(data);
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void doGetSandboxSignKey() throws Exception {
        WXPayConfigImpl config = WXPayConfigImpl.getInstance();
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        String sign = WXPayUtil.generateSignature(data, config.getKey());
        data.put("sign", sign);
        WXPay wxPay = new WXPay(config);
        String result = wxPay.requestWithoutCert("https://api.mch.weixin.qq.com/sandbox/pay/getsignkey", data, 10000, 10000);
        System.out.println(result);
    }


//    public void doReport() {
//        HashMap<String, String> data = new HashMap<String, String>();
//        data.put("interface_url", "20160822");
//        data.put("bill_type", "ALL");
//    }

    /**
     * 小测试
     */
    public void test001() {
        String xmlStr = "<xml><return_code><![CDATA[SUCCESS]]></return_code>\n" +
                "<return_msg><![CDATA[OK]]></return_msg>\n" +
                "<appid><![CDATA[wx273fe72f2db863ed]]></appid>\n" +
                "<mch_id><![CDATA[1228845802]]></mch_id>\n" +
                "<nonce_str><![CDATA[lCXjx3wNx45HfTV2]]></nonce_str>\n" +
                "<sign><![CDATA[68D7573E006F0661FD2A77BA59124E87]]></sign>\n" +
                "<result_code><![CDATA[SUCCESS]]></result_code>\n" +
                "<openid><![CDATA[oZyc_uPx_oed7b4q1yKmj_3M2fTU]]></openid>\n" +
                "<is_subscribe><![CDATA[N]]></is_subscribe>\n" +
                "<trade_type><![CDATA[NATIVE]]></trade_type>\n" +
                "<bank_type><![CDATA[CFT]]></bank_type>\n" +
                "<total_fee>1</total_fee>\n" +
                "<fee_type><![CDATA[CNY]]></fee_type>\n" +
                "<transaction_id><![CDATA[4008852001201608221983528929]]></transaction_id>\n" +
                "<out_trade_no><![CDATA[20160822162018]]></out_trade_no>\n" +
                "<attach><![CDATA[]]></attach>\n" +
                "<time_end><![CDATA[20160822202556]]></time_end>\n" +
                "<trade_state><![CDATA[SUCCESS]]></trade_state>\n" +
                "<cash_fee>1</cash_fee>\n" +
                "</xml>";
        try {
            System.out.println(xmlStr);
            System.out.println("+++++++++++++++++");
            System.out.println(WXPayUtil.isSignatureValid(xmlStr, config.getKey()));
            Map<String, String> hm = WXPayUtil.xmlToMap(xmlStr);
            System.out.println("+++++++++++++++++");
            System.out.println(hm);
            System.out.println(hm.get("attach").length());

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void testUnifiedOrderSpeed() throws Exception {
        WXPayAgent dodo = new WXPayAgent("201212121002", 1);

        for (int i = 0; i < 100; ++i) {
            long startTs = System.currentTimeMillis();
            out_trade_no = out_trade_no + i;
            dodo.doUnifiedOrder();
            long endTs = System.currentTimeMillis();
            System.out.println(endTs - startTs);
            Thread.sleep(1000);
        }

    }

    public static void main(String[] args) throws Exception {
//        System.out.println("--------------->");
        WXPayAgent dodo = new WXPayAgent("200001020125321132", 1);
        dodo.doXcxUnifiedOrder("");
//        // dodo.doOrderQuery();
//        // dodo.doDownloadBill();
//        // dodo.doShortUrl();
//        // dodo.test001();
//        // dodo.doOrderQuery();
//        // dodo.doOrderClose();
//        // dodo.doRefund();
//        // dodo.doRefundQuery();
//        // dodo.doOrderReverse();
//        // dodo.test001();
//        // dodo.testUnifiedOrderSpeed();
//
////        dodo.doOrderQuery();
////        dodo.doOrderReverse();
////        dodo.doOrderQuery();
////        dodo.doOrderReverse();
////        dodo.doOrderQuery();
//
//
//        System.out.println("<---------------"); // wx2016112510573077
//        System.out.println("<------- 退款通知解密测试 -------->");
//        String A = "oSWxqqMF5lk2EF+gdrdt5wPrOru854za5XjHq5cUXs74zF9+jlxGOo7DHQIuntolVF3kQAruoMoNK5lLRsCulgG2hAT+6sNen8f/f3drMxfsTFOj3aBTKkIHs2p3AVJA4fXpGRCpejq3JJplSQnnSwFljzcxvqe7rU3y/H0KpFyBuYUSEf+msbkHEnHnIHQi4p9JDlLPWoKHramM7R65Qd13GdUU41scNybWCkwl+q/cY2Nv6KUt490JXTbTEgZNE6ArJKGg9woRMUdJEimTnv2OSY16yjo8dlIiozEoHcoQsvSFuMA5DHfHmtk5gbn8y6FVLHbt8XmmOIkfl/CVCXGQ+fGJmazxmqpTLBnAxXogFX2c2h8ZFqrWHW0wWZNSqpRX8HnMBw4V5hUMCiN9ASP3AzkpbtxdkDaeJYagVFgpB7oXxNUlQMy7pCqWCqbhoeLlZtzACx3qNqf57cQLn06T8wrYddf3f78oIYceVWMBses6wcJW2uTUdci4hYOQn5G+iVGLRzMuI8xwQSeBtdrWBor842tEsg4/wgFRxiEgjN+Jl+pCbwULjzt870OwC/UKD9mM3bhyay1jxeKNfkqgks0TH9eZXT1mR6IBfIUipgk9nTrGLFQwt4AAAf7/KoW7A3d1eYGY1vo/QkinixiZsxOJhzw95X6wiiARPa8oe0180lCuhLtIrNRlxyVMbbwA8GQVuCCE6w+/yKIF+el+Gcf7Gm2ljQzV7PEwiomW/DsBqUb5mwGfI52NLRa70kJ8vgaXeMN1xhwWYLzg02muvGGwS2P4kgGO0Sg0L5ycpN7Vp421+HnAPdcW6y/pQi03BKAR6fZT5JQYAIoNN4K8K6ZbgfZiuG32q0q4bwVWrg4jBlyPmj8JwHtbikbAgoJ9sUwWYi7P+Btk1ZHCPLW90p+1mIL8eVpneOaon3mSW0R4JDiIJK8oYLD/1n4NTKRTg9c6OMdSHnK8BUnodw==";
//        System.out.println(A);
//        System.out.println("<-------------------------------->");
//        String a = "鏀\uE219粯鐢ㄦ埛闆堕挶";
//        System.out.println(new String(a.getBytes("GBK"),"UTF-8"));


    }
}
